#include "AggPlotter.hpp"

#include <algorithm>

AggPlotter::AggPlotter(): kCfg(0), frame_width(2000), frame_height(1200)
{   }

void AggPlotter::readConfig(std::string fname)
{
    std::ifstream infile(fname.c_str(), std::ios_base::in);
    std::string temp, line;
    std::vector<std::string> file;
    
    while (getline(infile, line, '\n'))
    {
        file.push_back(line);
    }
    
    if (file.size() > 21) {
        std::stringstream iss(std::stringstream::in | std::stringstream::out);
        iss << file[1] << file[3] << file[5] << file[7];
        iss >> cfgNum >> cfgType >> cfgIX1 >> cfgIY1 >> cfgIX2 >> cfgIY2;
        
        cfgNameX = file[9];
        cfgNameX.erase(std::remove_if(cfgNameX.begin(), cfgNameX.end(), isspace), cfgNameX.end());
        
        cfgNameY = file[10];
        cfgNameY.erase(std::remove_if(cfgNameY.begin(), cfgNameY.end(), isspace), cfgNameY.end());
        
        iss.clear(); iss << file[12];
        iss >> cfgX1 >> cfgX2 >> cfgX0 >> cfgXStep >> cfgXScale;
        
        iss.clear(); iss << file[13];
        iss >> cfgY1 >> cfgY2 >> cfgY0 >> cfgYStep >> cfgYScale;
        
        cfgNameZ = file[15];
        cfgNameZ.erase(std::remove_if(cfgNameZ.begin(), cfgNameZ.end(), isspace), cfgNameZ.end());
        
        iss.clear(); iss << file[17];
        iss >> cfgZ1 >> cfgZ2;
        
        iss.clear(); iss << file[19];
        iss >> cfgIZ1 >> cfgIZ2;
        
        iss.clear(); iss << file[21];
        iss >> cfgRepeatY;
        
        kCfg = 1;
    }
    
    std::cout << "IX2 IY2: <" << cfgIX2 << "> <"<< cfgIY2 << ">\n";
    std::cout << "Names: <" << cfgNameX << "> <"<< cfgNameY << "> <" << cfgNameZ << ">\n";
    std::cout << "IZ1 IZ2: <" << cfgIZ1 << "> <"<< cfgIZ2 << ">\n";
}

void AggPlotter::plotParticles(std::string fname, std::vector<double> & xx, std::vector<double> & yy, std::vector<double> & dd, std::vector<double> & vv)
{
    /*
        timing
    */
    
    int i, j;
    
    double t0, t1, t2, t3;
    
    /*
        renderer
    */
    
    typedef agg::pixfmt_rgb24                     pixfmt_type;
    typedef agg::renderer_base<agg::pixfmt_rgb24> renbase_type;
    typedef agg::renderer_primitives<renbase_type> renprim_type;
    typedef agg::glyph_raster_bin<agg::rgba> glyph_gen;
    glyph_gen glyph(0);
    
    enum { bytes_per_pixel = 3 };

    unsigned char* buffer = new unsigned char[frame_width * 
                                              frame_height * 
                                              bytes_per_pixel];
    
    agg::rendering_buffer rbuf(buffer, 
                               frame_width, 
                               frame_height, 
                               frame_width * bytes_per_pixel);
    
    pixfmt_type pixf(rbuf);
    renbase_type rbase(pixf);
    renprim_type rprim(rbase);

    agg::rgba8 clear_color(255, 255, 255);
    
    /* 
        render
    */
    
    rbase.clear(clear_color);
    
    agg::rasterizer_scanline_aa<> pf;
    agg::scanline_p8 sl;

    int num = xx.size();
    
    t1 = get_time();
    
    double min_x=0, min_y=0, max_x=0, max_y=0;
    double max_p = 0;
    double v_x, v_y,v_d,v_p;
    
    for(i = 0; i < num; ++i){
        v_x = xx[i];
        v_y = yy[i];
        v_p = vv[i];
        if(v_x < min_x) min_x = v_x;
        if(v_y < min_y) min_y = v_y;
        if(v_x > max_x) max_x = v_x;
        if(v_y > max_y) max_y = v_y;
        if(v_p > max_p) max_p = v_p;
    }
    
    double col_r, col_g, col_b;
    
    double scale_x, scale_y, scale_r;
    scale_x = frame_width / (max_x - min_x);
    scale_y = frame_height / (max_y - min_y);
    
    if(scale_x < scale_y) scale_r = scale_x;
    else scale_r = scale_y;
    
    t2 = get_time();
    //std::cout<<"X"<<min_x<<" "<<max_x<<"Y"<<min_y<<" "<<max_y<<"\n";
    //std::cout<<"Time to calc:"<<t2 - t1<<"\n";
    
    for(i = 0; i < num; ++i){
        v_x = xx[i];
        v_y = yy[i];
        v_p = vv[i];
        v_d = dd[i];
        
        agg::ellipse e1;
        double mr = 1.0;
        if(v_d * scale_r > 1.0) mr = v_d * scale_r;
        
        e1.init(v_x * scale_r, v_y * scale_r, mr, mr, 8);
        pf.add_path(e1);
        
        col_r = v_p / max_p;
        if(col_r < 0.0) col_r = 0.0;
        if(v_p / max_p > 0.5) col_g = (2.0 - 2.0 * v_p / max_p);
        else col_g = (2.0 * v_p / max_p );
        if(col_g < 0.0) col_g = 0.0;
        col_b = (1.0 - v_p / max_p);
        if(col_b < 0.0) col_b = 0.0;
        
        agg::render_scanlines_aa_solid(pf, sl, rbase, agg::rgba(col_r, col_g, col_b, 0.8));
        
        char buf[256];
        strcpy(buf, "Brown fox jumps over lazy dog");
        
        /*glyph.font(agg::verdana18);
        agg::renderer_raster_htext_solid<renbase_type , glyph_gen> rt2(rbase, glyph);
        rt2.render_text(5, 465, (unsigned char*)"RADIAL REPEATING GRADIENT: A quick brown fox jumps over the lazy dog", true);
        */
        
        //agg::render_scanlines_aa_solid(pf, sl, rbase, agg::rgba(0,0,0));
    }
    
    t3 = get_time();
    std::cout<<"Time to draw:"<<t3 - t2<<"\n";
    
    //rprim.solid_ellipse(100, 100, 20, 20);
    
    // Write a .ppm file
    FILE* fd = fopen(fname.c_str(), "wb");
    fprintf(fd, "P6\n%d %d\n255\n", rbuf.width(), rbuf.height());
    fwrite(buffer, 1, rbuf.width() * rbuf.height() * 3, fd);
    fclose(fd);

    delete [] buffer;
}

void AggPlotter::plotAxis()
{
    
}

void AggPlotter::plotLines(std::string fname, std::vector<double> & xx, std::vector<double> & yy, double x0=0.0)
{
    /*
        timing
    */
    
    int i, j;
    
    double t0, t1, t2, t3;
    
    /*
        renderer
    */
    
    typedef agg::pixfmt_rgb24                     pixfmt_type;
    typedef agg::renderer_base<agg::pixfmt_rgb24> renbase_type;
    typedef agg::renderer_primitives<renbase_type> renprim_type;
    typedef agg::glyph_raster_bin<agg::rgba> glyph_gen;
    glyph_gen glyph(0);
    
    enum { bytes_per_pixel = 3 };

    unsigned char* buffer = new unsigned char[frame_width * 
                                              frame_height * 
                                              bytes_per_pixel];
    
    agg::rendering_buffer rbuf(buffer, 
                               frame_width, 
                               frame_height, 
                               frame_width * bytes_per_pixel);
    
    pixfmt_type pixf(rbuf);
    renbase_type rbase(pixf);
    renprim_type rprim(rbase);

    agg::rgba8 clear_color(255, 255, 255);
    
    /* 
        render
    */
    
    plotAxis();
    
    rbase.clear(clear_color);
    
    agg::rasterizer_scanline_aa<> pf;
    agg::scanline_p8 sl;
    
    /*  axis */
    
    agg::path_storage path;

    path.move_to(100, 100);
    path.line_to(100,800);
    path.line_to(1200, 800);
    path.line_to(1200, 100);
        
    path.close_polygon();
    
    agg::conv_stroke<agg::path_storage> stroke(path);
    stroke.width(2.0);
    pf.add_path(stroke);
    
    agg::render_scanlines_aa_solid(pf, sl, rbase, agg::rgba(0.4, 0.4, 0.9, 0.9));

    int num = xx.size();
    
    t1 = get_time();
    
    double min_x=0, min_y=0, max_x=0, max_y=0;
    double max_p = 0;
    double v_x, v_y,v_d,v_p;
    
    for(i = 0; i < num; ++i){
        v_x = xx[i];
        v_y = yy[i];
        if(v_x < min_x) min_x = v_x;
        if(v_y < min_y) min_y = v_y;
        if(v_x > max_x) max_x = v_x;
        if(v_y > max_y) max_y = v_y;
    }
    
    double col_r, col_g, col_b;
    
    double scale_x, scale_y, scale_r;
    scale_x = frame_width / (max_x - min_x);
    scale_y = frame_height / (max_y - min_y);
    
    t2 = get_time();
    //std::cout<<"X"<<min_x<<" "<<max_x<<"Y"<<min_y<<" "<<max_y<<"\n";
    //std::cout<<"Time to calc:"<<t2 - t1<<"\n";
    
    for(i = 0; i < num; ++i){
        v_x = xx[i];
        v_y = yy[i];
        
        agg::ellipse e1;
        double mr = 3.0;
        
        e1.init(v_x * scale_x, frame_height - (v_y - min_y) * scale_y, mr, mr, 8);
        pf.add_path(e1);

        agg::render_scanlines_aa_solid(pf, sl, rbase, agg::rgba(0.4, 0.4, 0.4, 0.9));
    }
    
    if(x0 > min_x){
        for(i = 0; i < 100; ++i){
            v_x = x0;
            v_y = min_y + i * (max_y - min_y) * 0.01;
            
            agg::ellipse e1;
            double mr = 3.0;
            
            e1.init(v_x * scale_x, frame_height - v_y * scale_y, mr, mr, 8);
            pf.add_path(e1);

            agg::render_scanlines_aa_solid(pf, sl, rbase, agg::rgba(0.6, 0.2, 0.2, 0.9));
        }
    }
    
    t3 = get_time();
    std::cout<<"Time to draw:"<<t3 - t2<<"\n";
    
    //rprim.solid_ellipse(100, 100, 20, 20);
    
    // Write a .ppm file
    FILE* fd = fopen(fname.c_str(), "wb");
    fprintf(fd, "P6\n%d %d\n255\n", rbuf.width(), rbuf.height());
    fwrite(buffer, 1, rbuf.width() * rbuf.height() * 3, fd);
    fclose(fd);

    delete [] buffer;
}

void AggPlotter::saveFile(std::string fname)
{
    
}